<?php
// +----------------------------------------------------------------------
// | title: 标题注释
// +----------------------------------------------------------------------
// | Author: TZ.Leong
// +----------------------------------------------------------------------
// | Date: 2019/7/2 10:38
// +----------------------------------------------------------------------

namespace app\single\controller;

use app\admin\model\ApiOperateModel;
use app\single\model\CrossNodesModel;
use app\single\model\PayLogModel;
use app\single\model\PayModel;
use app\single\model\RoleModel;
use app\single\model\VarModel;
use think\Db;
use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;
use think\exception\DbException;
use think\facade\Cache;
use think\facade\Log;
use think\facade\Request;

class RpcController extends \app\admin\controller\RpcController
{
    /**
     * 同步服务器列表
     * @param $info
     * @return bool
     */
    public function sendToServer($info): bool
    {
        $data = unserialize($info);
        if (empty($data) || !$this->cipher($data)) {
            Log::write("debug send to server sign error" . $data["platform"] . "_____" . PLATFORM . __LINE__, "error");
            return false;
        }

        if ($data["platform"] != PLATFORM || $data["plat_server"] != PLAT_SERVER_ID) {
            Log::write("debug send to server" . $data["platform"] . "_____" . PLATFORM . __LINE__, "error");
            return false;
        }

        return Cache::store("file")->set("server_info", $data);
    }

    /**
     * @param $info
     * @return bool
     */
    public function auditSendRequest($info)
    {
        $data = unserialize($info);
        // Log::write("debug auditSendRequest recvied data" . json_encode($data, true));
        if (empty($data)) {
            // Log::write("debug empty data", 'error');
            return false;
        }
        if (!$this->cipher($data)) {
            // Log::write("debug sign error", 'error');
            return false;
        }

        $roleModel = new RoleModel();
        //获取玩家信息
        $playerId = $roleModel->where("id", $data["player_id"])->value("id");
        //玩家不存在
        if (empty($playerId)) {
            // Log::write("debug player  error", 'error');
            return false;
        }

        //道具内容，数组
        $sendInfoArr = [];
        // Log::write("debug  rpc data".json_encode($data,true));
        if (!empty($data["send_info"])) {
            $sendInfoArr = json_decode($data["send_info"], true);
            //如果是充值道具，则设置为模拟充值
            if (isset($sendInfoArr["charge_type"])) {
                $data["type"] = 3;
            }
        }else {
            // Log::write("debug  send_info is null".json_encode($data["send_info"],true));
        }


        //模拟充值
        if ($data["type"] == 3) {
            //选择游戏内充值类型模拟充值
            if (isset($sendInfoArr["charge_type"])) {
                $chargeType = (int)$sendInfoArr["charge_type"];
                $num = (int)$sendInfoArr["num"];
            } else {
                $chargeType = 1;
                $num = 0; //可能申请多次元宝，要累加起来
                foreach ($sendInfoArr as $vo) {
                    if (isset($vo["code"]) && $vo["code"] == 2) {
                        $num += $vo["num"];
                    }
                }
                $sendInfoArr = [];
            }
            $sendResult = moniPay($playerId, $num, $chargeType, $sendInfoArr);
        } else { //邮件发送道具
            //邮件标题和内容
            // $sendInfoArr = json_decode($data["send_info"], true);
            $title = $data['title'] ?? '系统邮件';
            $content = $data['content'] ?? '祝您游戏愉快！';
            $mail_type = $data['mail_type'] ?? 1;
            // Log::write("debug  send_info is null".json_encode($data["send_info"],true));
            $sendResult = sendItemReward($playerId, $sendInfoArr, $title, $content, $mail_type);
        }

        return $sendResult;
    }

    /**
     * 获取开服时间
     * @return bool|string
     */
    public function getInstallTime($data)
    {
        if (!$this->cipher($data)) {
            return false;
        }

        $scriptPath = CMF_ROOT . "/sh/";
        exec("cd {$scriptPath}; sh restart_game.sh cat_game_open_time " . PLATFORM . " " . PLAT_SERVER_ID, $shellArr);
        $success = array_pop($shellArr);
        $this->_log("debug open time: " . $success);
        return (string)$success;
    }

    /**
     * 设置最新服
     * @param $serverInfo
     * @return bool
     */
    public function setMaxServer($serverInfo)
    {
        if (!$this->cipher($serverInfo)) {
            return false;
        }

        $varModel = new VarModel();
        $value = '[<<"' . $serverInfo["ip"] . '">>,' . $serverInfo["port"] . ',<<"' . $serverInfo["socket"] . '">>,' . $serverInfo["plat_server"] . ']';
        if (false !== $varModel->replaceData("new_server", $value)) {
            PHP2Erlang(BACKGROUP_REFRESH_NEW_SERVER);
            return true;
        }

        return false;
    }

    public function _log($msg): void
    {
        Log::write("msg: $msg " . $this->clientIp, "error", false, Request::controller() . "_" . Request::action() . "_" . date("Ymd") . ".log");
    }

    /**
     * 充值请求发货
     * @param $content
     * @return array
     * @throws DbException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function pay($content)
    {
        $data = json_decode(urldecode($content), true);
        if (!$this->cipher($data)) {
            return array("ret" => STATUS_RPC_FAILED, "msg" => "权限验证失败!");
        }

        $payModel = new PayModel();
        $payLogModel = new PayLogModel();
        $roleModel = new RoleModel();

        //检查玩家是否存在
        $playerInfo = $roleModel->where("id", $data["player_id"])
            ->field("id AS role_id,lev as now_level ,cur_id as now_round")
            ->find();

        // Log::write("debug player info " . json_encode($playerInfo->toArray(), true) . __LINE__);
//        Log::write("debug playerInfo: " . $playerInfo . 'last query sql ' . $roleModel->getLastSql());
        if (empty($playerInfo)) {
            return array("ret" => STATUS_PLAYER_NOT_EXIST, "msg" => "该玩家不存在!");
        }
        $playerInfo = $playerInfo->toArray();

        //检查订单号是否存在
        $checkPayLog = $payLogModel->where("order_id", $data["order_id"])
            ->whereOr("cp_order_id", $data["cp_order_id"])
            ->find();
        if ($checkPayLog) {
            return array("ret" => STATUS_ORDER_DUPLICATE, "msg" => "该订单号已存在!");
        }

        //记录充值信息
        $payData = array_merge($data, $playerInfo);
        //是否写充值记录
        $isPayLog = $payData["is_pay_log"] ?? IS_RECORD_PAY;
        //开始发元宝
        $payData["pay_date"] = date("Ymd", $data["pay_time"]);
//        $hookInfo = Db::table(config("database.game") . ".role_auto_fight")
//            ->where("role_id", $data["player_id"])
//            ->find();
//        $payData["now_hook_id"] = $hookInfo["id"] ?? 1;
        $this->_log("payData::::x" . json_encode($payData));

        //正常充值，要写流水
        if ($isPayLog == IS_RECORD_PAY) {
            $payRet = $payModel->addPay($data["player_id"], $data["charge_type"], $data["gold"], $data["rmb"], $payData);
        } //只写流水
        elseif ($isPayLog == RECORD_BUT_NO_PAY) {
            $res = $payLogModel->addPayLog($payData);
            $payRet = $res ? ["ret" => STATUS_SUCCESS] : ["ret" => STATUS_DELIVERY_FAILED];
            if (!$res) {
                $this->_log(STATUS_DELIVERY_FAILED . json_encode($payData));
            }
        } //只发货不写流水
        else {
            $payRet = $payModel->addPay($data["player_id"], $data["charge_type"], $data["gold"], 0, $payData);
        }

//        $this->_log("payRet::::x" . json_encode($payRet) . "paydata" . json_encode($payData));

        return $payRet["ret"] == STATUS_SUCCESS ?
            array("ret" => STATUS_SUCCESS, "msg" => "发货成功!") :
            array("ret" => $payRet["ret"], "msg" => "充值发货失败!");
    }

    /**
     * 获取玩家表数据
     * @param $data [
     *      role_id
     *      type : 1-角色等级
     *      field : role表查询字段
     * ]
     * @return int
     * @throws \Exception
     */
    public function getRoleData($data)
    {
        if (!$this->cipher($data)) {
            return 0;
        }

        $roleId = $data["role_id"];
        $res = PHP2Erlang(BACKGROUND_GET_ROLE_INFO, [$roleId, $data["type"]]);
        if ($res["code"] === 0) {
            $value = $res["data"];
        } else {
            //从数据库取
            $roleModel = new RoleModel();
            $value = $roleModel->where("id", $roleId)->value($data["field"]);
        }

        return (int)$value;
    }

    /**
     * 通知好友 任务类型
     * @param $data [
     *      role_id
     *      type : 目标类型
     *      value : 目标达标值
     * ]
     * @return bool
     * @throws \Exception
     */
    public function setFriendData($data)
    {
        if (!$this->cipher($data)) {
            return false;
        }

        $res = PHP2Erlang(BACKGROUND_FRIEND_TASK, [$data["role_id"], $data["type"], $data["value"]]);
        return $res["code"] === 0;
    }

    /**
     * 校验红包余额并且扣除
     * @param $data
     * @return bool
     * @throws \Exception
     */
    public function checkRoleData($data)
    {
        if (!$this->cipher($data)) {
            return false;
        }

        $res = PHP2Erlang(BACKGROUND_ADDITEM, [$data["player_id"], $data["amount"]]);
        return $res["code"] === 0;
    }

    /**
     * 封禁玩家角色
     * @param $data [
     *      role_id
     * ]
     * @return bool
     * @throws DbException
     * @throws DataNotFoundException
     * @throws ModelNotFoundException
     */
    public function banRole($data)
    {
        if (!$this->cipher($data)) {
            return false;
        }

        //查询玩家状态
        $model = new RoleModel();
        $roleInfo = $model->where("id", $data["role_id"])->field("state")->find();
        if (!$roleInfo) {
            return false;
        }

        if ($roleInfo["state"] == 1) {
            return true;
        }

        //通知封号
        $res = PHP2Erlang(BACKGROUND_LOGIN_BAN, [1, $data["role_id"]]);
        if ($res["code"] === 0) {
            //操作日志
            $apiModel = new ApiOperateModel();
            $apiModel->addApiLog(1, json_encode(array("reason" => "api操作封号")), $data["role_id"]);
            return true;
        }

        return false;
    }

    /**
     * 解封玩家角色
     * @param $data [
     *      role_id
     * ]
     * @return bool
     */
    public function cancelBanRole($data)
    {
        if (!$this->cipher($data)) {
            return false;
        }

        //查询玩家状态
        $model = new RoleModel();
        $roleInfo = $model->where("id", $data["role_id"])->field("state")->find();
        if (!$roleInfo) {
            return false;
        }

        if ($roleInfo["state"] == 0) {
            return true;
        }

        //通知解封角色
        $res = PHP2Erlang(BACKGROUND_LOGIN_BAN, [0, $data["role_id"]]);
        if ($res["code"] === 0) {
            //操作日志
            $apiModel = new ApiOperateModel();
            $apiModel->addApiLog(1, json_encode(array("reason" => "api操作解封")), $data["role_id"]);
            return true;
        }

        return false;
    }

    /**
     * 禁言
     * @param $data [
     *      role_id
     *      duration : 禁言时长
     * ]
     * @return bool
     */
    public function shutupRole($data)
    {
        if (!$this->cipher($data)) {
            return false;
        }

        $model = new RoleModel();
        $roleInfo = $model->where("id", $data["role_id"])->field("ban_talk_time")->find();
        if (!$roleInfo) {
            return false;
        }

        if ($roleInfo["ban_talk_time"] > time()) {
            //已经被禁言
            return true;
        }

        $res = PHP2Erlang(BACKGROUND_CHAT_BAN, [1, $data["role_id"], (int)$data["duration"]]);
        return $res["code"] === 0;
    }

    /**
     * 设置跨服节点
     * @param $data [
     *      cross_type : 跨服类型
     *      node: 节点 'xymxh5_cross_s100001@192.168.0.209','xymxh5_cross_s100001_smck'
     * ]
     * @return bool
     */
    public function setCrossService($data)
    {
        if (!$this->cipher($data)) {
            return false;
        }

        list($node, $cookie) = explode(",", $data["node"]);
        try {
            $model = new CrossNodesModel();
            if (false != $model->where(array("cross_type" => $data["cross_type"]))->delete()) {
                if ($model->insert(array("cross_type" => $data["cross_type"], "node" => $node, "cookie" => $cookie))) {
                    PHP2Erlang(BACKGROUND_CROSS_NODES_CHANGE);
                    return true;
                }
            }
        } catch (\Exception $e) {
            return false;
        }

        return false;
    }

    /**
     * 删除跨服节点
     * @param $data [
     *      cross_type : 跨服类型
     * ]
     * @return bool
     */
    public function deleteCross($data)
    {
        if (!$this->cipher($data)) {
            return false;
        }

        try {
            $model = new CrossNodesModel();
            if ($model->where(array("cross_type" => $data["cross_type"]))->delete()) {
                PHP2Erlang(BACKGROUND_CROSS_NODES_CHANGE);
                return true;
            }
        } catch (\Exception $e) {
            return false;
        }

        return false;
    }

    /**
     * 执行sql语句
     * @param $data
     * @return array|mixed
     */
    public function executeSql($data)
    {
        if (!$this->cipher($data)) {
            return false;
        }

        try {
            //替换sql里面的数据库标识
            $sql = str_replace(
                ['GAME_DB', 'LOG_DB'],
                [config("database.game"), config("database.log")],
                $data["sql"]
            );

            //严格检测sql是select开头
            if (preg_match('/^(SELECT)\s+.*/i', $sql)) {
                //如果是select，则用query执行
                return Db::query($sql);
            }

            if (preg_match('/^(ALTER)\s+.*/i', $sql)) {
                return Db::execute($sql);
            }
        } catch (\Exception $e) {
            return false;
        }

        return false;
    }
}